#include "stdafx.h"
#include "Game.h"
#include "menu\MainMenuState.h"
#include "menu\GameState.h"
#include "SGD Wrappers\SGD_AudioManager.h"
#include "SGD Wrappers\SGD_GraphicsManager.h"
#include "SGD Wrappers\SGD_InputManager.h"
#include "particles\ParticleManager.h"
#include "particles\Particle.h"
#include "Font.h"
#include "SGD Wrappers\SGD_EventManager.h"
#include "SGD Wrappers\SGD_MessageManager.h"
#include "SGD Wrappers\SGD_Message.h"
#include "SGD Wrappers\MessageID.h"
#include "tile\TileManager.h"
#include "ScoreMessage.h"
#include "CreatePunchMessage.h"
#include "SGD Wrappers\DestroyEntityMessage.h"
#include "menu/SaveGameState.h"
#include <ShlObj.h>
#include "menu\DodgeBomb.h"
#include "CreateScorpSpear.h"
#include "CreateGoalieMessage.h"
#include "menu/PracticeMode.h"
#define BUCKET_PLAYERS 0
#define BUCKET_ENEMIES 1
#define BUCKET_GORBI 2
#define BUCKET_BALL 3
#define BUCKET_WALLS 4
#define BUCKET_POWERUPS 5

Game* Game::s_pInstance = nullptr;

Game* Game::GetInstance(void)
{
	if (s_pInstance == nullptr)
		s_pInstance = new Game;

	return s_pInstance;
}

void Game::DeleteInstance(void)
{
	delete s_pInstance;
	s_pInstance = nullptr;
}

bool Game::Initialize(float width, float height)

{
	if (SGD::AudioManager::GetInstance()->Initialize() == false
		|| SGD::GraphicsManager::GetInstance()->Initialize(false) == false
		|| SGD::InputManager::GetInstance()->Initialize() == false)
		return false;

	SGD::EventManager::GetInstance()->Initialize();

	srand((unsigned int)time(nullptr));
	rand();
	
	
	m_fScreenWidth = width;
	m_fScreenHeight = height;
	m_fWorldWidth = 800;
	m_fWorldHeight = 600;

	// Initialize the Message Manager
	SGD::MessageManager::GetInstance()->Initialize(&Game::MessageProc);

	SGD::AudioManager* pAudio = SGD::AudioManager::GetInstance();
	
	
	
	
	
	
	menu = pAudio->LoadAudio("soundfxs/buttonsound.wav");
	boom = pAudio->LoadAudio("soundfxs/boom.wav");
	powerup = pAudio->LoadAudio("soundfxs/powerup.wav");
	
	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();
	creatureatk = pAudio->LoadAudio("soundfxs/Creature_Attack.wav");
	creaturedie = pAudio->LoadAudio("soundfxs/Creature_Dies.wav");
	creaturegrowl = pAudio->LoadAudio("soundfxs/Creature_Growl.wav");
	hit = pAudio->LoadAudio("soundfxs/Get_Hit_01.wav");
	m_hScore = pAudio->LoadAudio("soundfxs/Score.wav");
	sprinting = pAudio->LoadAudio("soundfxs/sprinting.wav");
	
	tunes = pAudio->LoadAudio("soundfxs/Menu_Music.xwm");
	punchhit = pAudio->LoadAudio("soundfxs/punchhit.wav");
	punchmiss = pAudio->LoadAudio("soundfxs/punchmiss.wav");
	tackle = pAudio->LoadAudio("soundfxs/tackle.wav");
	dash = pAudio->LoadAudio("soundfxs/Dash.wav");
	throwing = pAudio->LoadAudio("soundfxs/throw.wav");
	exhausted = pAudio->LoadAudio("soundfxs/exhausted.wav");
	death = pAudio->LoadAudio("soundfxs/death.wav");
	walking = pAudio->LoadAudio("soundfxs/walking.wav");
	m_hGameSong = pAudio->LoadAudio("soundfxs/Main_Song.xwm");
	Arrow			= pGraphics->LoadTexture("pictures/arrow.bmp");
	m_hDarkSmoke	= pGraphics->LoadTexture("pictures/DarkSmoke.png");
	m_hLightSmoke	= pGraphics->LoadTexture("pictures/LightSmoke.png");
	m_hMedSmoke		= pGraphics->LoadTexture("pictures/MedSmoke.png");

	pAudio->PlayAudio(tunes, true);

	
	m_pFont = new Font;
	m_pFont->Initialize();
	
	
	

	m_ulGameTime = GetTickCount();

	HRESULT hr;
	char path[MAX_PATH];
	LPWSTR wszPath = NULL;
	size_t size;
	std::string pathtowrite;

	// Get the path to the AppData folder
	hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, 0, &wszPath);

	// convert from LPWSTR to char[]
	// parameters: Size of path, the destination for the path, the max size the dest
	//				could be, the source of the path, the max size in bytes
	wcstombs_s(&size, path, MAX_PATH, wszPath, MAX_PATH);

	// Convert char types
	pathtowrite = path;

	// Add team and game name
	pathtowrite += "\\I Forget\\National Bomb Ball League\\";

	wchar_t newPath[MAX_PATH];

	mbstowcs_s(&size, newPath, MAX_PATH, pathtowrite.c_str(), MAX_PATH);

	// Create the directory
	SHCreateDirectoryEx(NULL, newPath, 0);

	char* tempChar = new char[MAX_PATH];
	char defChar = ' ';
	WideCharToMultiByte(CP_ACP, 0, newPath, MAX_PATH, tempChar, size, &defChar, NULL);

	m_szPath = tempChar;

	delete tempChar;

	

	ChangeState(CMainMenuState::GetInstance());

	m_ulGameTime = GetTickCount();
	
	return true;
}

int Game::Update(void)
{
	if (SGD::AudioManager::GetInstance()->Update() == false
		|| SGD::GraphicsManager::GetInstance()->Update() == false
		|| SGD::InputManager::GetInstance()->Update() == false)


		SGD::InputManager* pInput = SGD::InputManager::GetInstance();
	SGD::AudioManager* pAudio = SGD::AudioManager::GetInstance();
	
		
	
	unsigned long now = GetTickCount();
	
	m_fElapsedTime = (now - m_ulGameTime) / 1000.0f;
	m_ulGameTime = now;

	
	if (m_fElapsedTime > 0.125f)
		m_fElapsedTime = 0.125f;
	
	//Get Graphics manager
	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();
	
	CIMenuState* pCurrent = m_pCurrState;
	if (m_pCurrState->Input() == false)
		return 1;

	SGD::EventManager::GetInstance()->Update();
	SGD::MessageManager::GetInstance()->Update();

	if (m_pCurrState == pCurrent)
	{
		
		m_pCurrState->Update(m_fElapsedTime);
		m_pCurrState->Render();
	}


	return 0;
}

/*static*/ void Game::MessageProc(const SGD::Message* pMsg)
{
	switch (pMsg->GetMessageID())
	{
	case MessageID::MSG_DESTROY_ENTITY:
	{
										  // Downcast to the actual message type
										  const DestroyEntityMessage* pDestroyMsg =
											  dynamic_cast<const DestroyEntityMessage*>(pMsg);

										  assert(pDestroyMsg != nullptr
											  && "Game::MessageProc - MSG_DESTROY_ENTITY is not actually a DestroyEntityMessage");

										  Entity* ptr = pDestroyMsg->GetEntity();

										  if (CPracticeMode::GetInstance()->GetEManager() != nullptr)
											  CPracticeMode::GetInstance()->DeleteEntity(ptr);
										  else if (Game::GetInstance()->GetMiniGame() == false)										  
											  CGameState::GetInstance()->DeleteEntity(ptr);										  
										  else
											  CDodgeBomb::GetInstance()->DeleteEntity(ptr);							  
	
										  
	}
		break;
	case MessageID::MSG_SCORE:
	{
								 if (dynamic_cast<const ScoreMessage*>(pMsg)->GetTeam() == 3)
								 {
									 CGameState::GetInstance()->BlueScore();
									 CSaveGameState::GetInstance()->SetBlue();
								 }
								 else if (dynamic_cast<const ScoreMessage*>(pMsg)->GetTeam() == 4)
								 {
									 CGameState::GetInstance()->RedScore();
									 CSaveGameState::GetInstance()->SetRed();
								 }
	}
		break;

	case MessageID::MSG_PUNCH:
	{
								 const CreatePunchMessage* pCreateMsg =
									 dynamic_cast<const CreatePunchMessage*>(pMsg);

								 if (CPracticeMode::GetInstance()->GetEManager() != nullptr)
								 {
									 Entity* ptr = CPracticeMode::GetInstance()->CreatePunch(pCreateMsg->GetOwner());
									 ptr->Release();
									 ptr = nullptr;
								 }
								 else if (Game::GetInstance()->GetMiniGame() == false)
								 {
									Entity* ptr = CGameState::GetInstance()->CreatePunch(pCreateMsg->GetOwner());
									ptr->Release();
									ptr = nullptr;
								 }
								 else
								 {
									 Entity* ptr = CDodgeBomb::GetInstance()->CreatePunch(pCreateMsg->GetOwner());
									 ptr->Release();
									 ptr = nullptr;
								 }

								
	}
		break;

	case MessageID::MSG_CREATE_SCORP_SPEAR:
	{
											  const CreateScorpSpear* pCreateMsg =
												  dynamic_cast<const CreateScorpSpear*>(pMsg);

											  Entity* ptr = CGameState::GetInstance()->CreateScorpSpear(pCreateMsg->GetOwner(), pCreateMsg->GetLevel());
											  ptr->Release();
											  ptr = nullptr;
	}
		break;

	case MessageID::MSG_CREATE_GOALIE:
	{
										 const CreateGoalieMessage* pCreateMsg =
											 dynamic_cast<const CreateGoalieMessage*>(pMsg);

										 Entity* ptr = CGameState::GetInstance()->CreateGoalie(pCreateMsg->GetOwner());
										 ptr->Release();
										 ptr = nullptr;
	}
		break;
	}
}

void Game::Terminate(void)
{
	CParticleManager::GetInstance()->Terminate();
	CParticleManager::GetInstance()->DeleteInstance();

	ChangeState(nullptr);

	m_pFont->Terminate();
	delete m_pFont;
	m_pFont = nullptr;
		
	CTileManager::GetInstance()->DeleteInstance();	

	
	
	
	SGD::AudioManager::GetInstance()->UnloadAudio(creatureatk);
	SGD::AudioManager::GetInstance()->UnloadAudio(creaturedie);
	SGD::AudioManager::GetInstance()->UnloadAudio(creaturegrowl);
	SGD::AudioManager::GetInstance()->UnloadAudio(hit);
	SGD::AudioManager::GetInstance()->UnloadAudio(tunes);
	SGD::AudioManager::GetInstance()->UnloadAudio(m_hGameSong);
	SGD::AudioManager::GetInstance()->UnloadAudio(m_hScore);
	SGD::AudioManager::GetInstance()->UnloadAudio(sprinting);
	SGD::AudioManager::GetInstance()->UnloadAudio(menu);
	SGD::AudioManager::GetInstance()->UnloadAudio(boom);
	SGD::AudioManager::GetInstance()->UnloadAudio(powerup);
	SGD::AudioManager::GetInstance()->UnloadAudio(punchhit);
	SGD::AudioManager::GetInstance()->UnloadAudio(punchmiss);
	SGD::AudioManager::GetInstance()->UnloadAudio(tackle);
	SGD::AudioManager::GetInstance()->UnloadAudio(dash);
	SGD::AudioManager::GetInstance()->UnloadAudio(throwing);
	SGD::AudioManager::GetInstance()->UnloadAudio(exhausted);
	SGD::AudioManager::GetInstance()->UnloadAudio(death);
	SGD::AudioManager::GetInstance()->UnloadAudio(walking);

	SGD::GraphicsManager::GetInstance()->UnloadTexture(m_hDarkSmoke);
	SGD::GraphicsManager::GetInstance()->UnloadTexture(m_hMedSmoke);
	SGD::GraphicsManager::GetInstance()->UnloadTexture(m_hLightSmoke);
	SGD::GraphicsManager::GetInstance()->UnloadTexture(Arrow);

	SGD::AudioManager::GetInstance()->Terminate();
	SGD::AudioManager::DeleteInstance();

	SGD::GraphicsManager::GetInstance()->Terminate();
	SGD::GraphicsManager::DeleteInstance();

	SGD::InputManager::GetInstance()->Terminate();
	SGD::InputManager::DeleteInstance();

	SGD::EventManager::GetInstance()->Terminate();
	SGD::EventManager::DeleteInstance();

	SGD::MessageManager::GetInstance()->Terminate();
	SGD::MessageManager::DeleteInstance();

	
}

void Game::ChangeState(CIMenuState* pNewState)
{
	if (m_pCurrState != nullptr)
		m_pCurrState->Exit();

	m_pCurrState = pNewState;

	if (m_pCurrState != nullptr)
		m_pCurrState->Enter();
}

float Game::LightOff()
{
	lightOffset += 10 * m_fElapsedTime;
	return lightOffset;
}

float Game::MedOff()
{
	medOffset += 10 * m_fElapsedTime;
	return medOffset;
}

float Game::DarkOff()
{
	darkOffset += 10 * m_fElapsedTime;
	return darkOffset;
}